#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h>
#include <error.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>

#include "external_sdk_client.h"
#include "external_sdk_client_http.h"
#include "cJSON.h"
#include "sha256.h"

static int Base64_Code(unsigned char *s,unsigned char *d)   
{   
	char CharSet[64]=   
	{   
        'A','B','C','D','E','F','G','H',   
        'I','J','K','L','M','N','O','P',   
        'Q','R','S','T','U','V','W','X',   
        'Y','Z','a','b','c','d','e','f',   
        'g','h','i','j','k','l','m','n',   
        'o','p','q','r','s','t','u','v',   
        'w','x','y','z','0','1','2','3',   
        '4','5','6','7','8','9','+','/'   
	};   
	unsigned char In[3];   
	unsigned char Out[4];   
	int cnt=0;   
	if(!s||!d) return 0;   
	for(;*s!=0;)   
	{   
        if(cnt+4>76)   
        {   
            *d++='\n';   
            cnt=0;   
        }   
        if(strlen((char*)s) >=3)   
        {   
            In[0]=*s;   
            In[1]=*(s+1);   
            In[2]=*(s+2);   
            Out[0]=In[0]>>2;   
            Out[1]=(In[0]&0x03)<<4|(In[1]&0xf0)>>4;   
            Out[2]=(In[1]&0x0f)<<2|(In[2]&0xc0)>>6;   
            Out[3]=In[2]&0x3f;   
            *d=CharSet[Out[0]];   
            *(d+1)=CharSet[Out[1]];   
            *(d+2)=CharSet[Out[2]];   
            *(d+3)=CharSet[Out[3]];   
            s+=3;   
            d+=4;   
        }   
        else if(strlen((char*)s)==1)   
        {   
            In[0]=*s;   
            Out[0]=In[0]>>2;   
            Out[1]=(In[0]&0x03)<<4|0;   
            *d=CharSet[Out[0]];   
            *(d+1)=CharSet[Out[1]];   
            *(d+2)='=';   
            *(d+3)='=';   
            s+=1;   
            d+=4;   
        }   
        else if(strlen((char*)s)==2)   
        {   
            In[0]=*s;   
            In[1]=*(s+1);   
            Out[0]=In[0]>>2;   
            Out[1]=(In[0]&0x03)<<4|(In[1]&0xf0)>>4;   
            Out[2]=(In[1]&0x0f)<<2|0;   
            *d=CharSet[Out[0]];   
            *(d+1)=CharSet[Out[1]];   
            *(d+2)=CharSet[Out[2]];   
            *(d+3)='=';   
            s+=2;   
            d+=4;   
        }   
        cnt+=4;   
	}   
	*d='\0';   
	return 1;   
}  


static int arrayToStr(uint32_t *buf, unsigned int buflen, char *out)
{
    char strBuf[512] = {0};
    char pbuf[512] = {0};
    int i = 0;
	
    for(i = 0; i < buflen; i++)
    {
        sprintf(pbuf, "%08x", buf[i]);
        strncat(strBuf, pbuf, 8);
    }
	
    strncpy(out, strBuf, buflen * 8);
	   
    return buflen * 8;
}


static char *GetJsonData(char *buf)
{
	char *res = NULL;
	int json_len = 0;

	if(NULL == buf)
	{
		printf("NULL\n");
		return NULL;
	}
	
	if(strlen <= 0)
	{
		printf("no data\n");
		return NULL;	
	}

	char* json_start = NULL;
	char* json_end = NULL;
	int i = 0; 

	json_start = strchr(buf, '{');
	for(i = strlen(buf); i >= 0; i--)
	{
		if(buf[i] == '}')
		{
			json_end = buf + i;
			break;
		}
	}

	if(json_start == NULL || json_end == NULL)
	{
		return NULL;
	}
	
	*(json_end + 1) = '\0';

	json_len = json_end - json_start + 1;
	
	res = malloc(json_len + 1);
	if(res != NULL)
	{
		strncpy(res, json_start, json_len);
		res[json_len] = '\0';
	}

	return res;
}

static int getDateTimeString(char *s_d_t, int s_len)
{
	time_t tt = time(0);
	//产生“YYYY-MM-DD hh:mm:ss”格式的字符串。
	strftime(s_d_t, s_len, "%Y-%m-%dT%H:%M:%S", localtime(&tt));
	return 0;
}

static int Sha256Encryption(ExternalSdkSha256* sha256)
{
	if(NULL == sha256 || NULL == sha256->outdata)
	{
		printf("param error pstSha256 %p, outdata %p\n", sha256, sha256->outdata);
		return -1;
	}
	
	/*第一轮加密          Date base64加密 date格式：YYYY-MM-DDThh:mm:ss   得到 DateBase64 字符串    */
	char base64DateTime[128] = {0};
	int base64len = 128;
	
	if(sha256->datetime && strlen(sha256->datetime)>0)
	{
		Base64_Code(sha256->datetime, base64DateTime);
	}
	else
	{
		base64len = 0;
	}

	char in_buf[1024] = {0};
	char out_buf[1024] = {0};
	uint32_t sha[8];
	
	sprintf(in_buf, "%s%s%s%s", (unsigned char *)sha256->username, (unsigned char *)sha256->license_key, (unsigned char *)base64DateTime, (unsigned char *)sha256->passwd);
	//printf("%s,%d:  in_buf=%s\n", __func__, __LINE__, in_buf);
	zsha256(in_buf, strlen(in_buf), sha);
	arrayToStr(sha, 8, out_buf);
	//printf("%s,%d: len=%d  out_buf=%s\n", __func__, __LINE__, strlen(out_buf), out_buf);
	
	memcpy(sha256->outdata, out_buf, strlen(out_buf));
	*sha256->outdatalen = strlen(out_buf);

	return 0;
}


int EXTERNAL_SDK_CLIENT_Login(ExternalSdkClientLoginInfo *login_info, char *session_id)
{	
	printf("%s,%d\n", __func__, __LINE__);
	char* response_content = NULL;
	char* json_data = NULL;
	ExternalSdkSha256 user_sha256 = {0};

    cJSON *dataJson = cJSON_CreateObject();
    if(dataJson == NULL)
    {
        printf("cJSON_CreateObject fail!\r\n");
        return -1;
    }

	char datetime[64] = {0};
	char cookie[128] = {0};	
	
	getDateTimeString(datetime, sizeof(datetime)-1);

	user_sha256.username = login_info->username;
	user_sha256.passwd = login_info->passwd;
	user_sha256.datetime = datetime;
	char out_pwd[256] = {0};
	user_sha256.outdata = out_pwd;
	int out_pwd_len = 256;
	user_sha256.outdatalen = &out_pwd_len;

	//LICENSE_KEY
	user_sha256.license_key = login_info->license_key;

	Sha256Encryption(&user_sha256);

	//printf("%s,%d  outdata:%s\n", __func__, __LINE__, out_pwd);
	
	cJSON_AddStringToObject(dataJson, "action", "set");

	cJSON *dataObject = cJSON_CreateObject();
	cJSON_AddStringToObject(dataObject, "username", login_info->username);
	cJSON_AddStringToObject(dataObject, "loginEncryptionType", "sha256-1");
	
	cJSON_AddStringToObject(dataObject, "password", out_pwd);
	cJSON_AddStringToObject(dataObject, "sessionID", session_id);
	cJSON_AddStringToObject(dataObject, "datetime", datetime);
	
	cJSON_AddItemToObject(dataJson, "data", dataObject);

    char *data_str  = cJSON_PrintUnformatted(dataJson);
	int  data_size = strlen(data_str);


	printf("%s,%d  data_str %s data_size %d\n", __func__, __LINE__, data_str, data_size);

	snprintf(cookie, sizeof(cookie), "sessionID=%s", session_id);
	
	response_content = client_http_post(login_info->url, login_info->port, data_str, cookie);
	if(NULL == response_content)
	{
		printf("response_content is null\n");
		return -1;
	}

	json_data = GetJsonData(response_content);
	if(NULL == json_data)
	{
		free(response_content);
		response_content = NULL;
		cJSON_Delete(dataJson);
		printf("json_data is null, response_content %s\n", response_content);
		return -1;
	}


	printf("%s,%d  login response %s\n", __func__, __LINE__, json_data);

	free(response_content);
	response_content = NULL;

	cJSON *root_json = cJSON_Parse(json_data);

	cJSON *data_json = cJSON_GetObjectItem(root_json, "data");

	strncpy(session_id, Json_GetStringFromObject(data_json, "cookie"), 128);	

	free(json_data);
	json_data = NULL;

	free(data_str);
	data_str = NULL;
	
	cJSON_Delete(dataJson);
	cJSON_Delete(root_json);

	return 0;
}


int EXTERNAL_SDK_CLIENT_Call(ExternalSdkClientCallParam *call_param, char **response)
{
	printf("%s,%d\n", __func__, __LINE__);
	char* response_content = NULL;
	char* json_data = NULL;

	printf("call_param->json_data %s\n", call_param->json_data);

	response_content = client_http_post(call_param->url, call_param->port, call_param->json_data, call_param->session_id);
	if(NULL == response_content)
	{
		printf("response_content is null\n");
		return -1;
	}

	json_data = GetJsonData(response_content);
	if(NULL == json_data)
	{
		free(response_content);
		response_content = NULL;
		printf("json_data is null, response_content %s\n", response_content);
		return -1;
	}

	printf("%s,%d  response %s\n", __func__, __LINE__, json_data);

	*response = json_data;

	free(response_content);
	response_content = NULL;
	
	return 0;
}


